#include "ipc.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring>
#include <stdexcept>
#include <chrono>

bool send_message(const std::string& socket_path, const Message& msg) {
    int sockfd = connect_to_server(socket_path);
    if (sockfd < 0) return false;

    ssize_t bytes_sent = send(sockfd, &msg, sizeof(Message), 0);
    close(sockfd);
    return bytes_sent == sizeof(Message);
}

bool receive_message(const std::string& socket_path, Message& msg) {
    static int server_fd = create_socket_server(socket_path);
    if (server_fd < 0) return false;

    struct sockaddr_un client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
    if (client_fd < 0) return false;

    ssize_t bytes_received = recv(client_fd, &msg, sizeof(Message), 0);
    close(client_fd);
    return bytes_received == sizeof(Message);
}

int create_socket_server(const std::string& socket_path) {
    unlink(socket_path.c_str());

    int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd < 0) {
        throw std::runtime_error("Failed to create socket");
    }

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1);

    if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        close(server_fd);
        throw std::runtime_error("Failed to bind socket");
    }

    if (listen(server_fd, 5) < 0) {
        close(server_fd);
        throw std::runtime_error("Failed to listen on socket");
    }

    return server_fd;
}

int connect_to_server(const std::string& socket_path) {
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd < 0) return -1;

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1);

    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        close(sockfd);
        return -1;
    }

    return sockfd;
}